package manager

import (
	log "ac-common-go/glog"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
	"time"
)

const (
	JSON_CONTENT_TYPE = "application/json"
	//
	//ZcObject            = "application/x-zc-object"
	//HEADER_DOMAIN_ID    = "x-zc-major-domain-id"
	//HEADER_SUBDOMAIN_ID = "x-zc-sub-domain-id"
	//HEADER_TIME_OUT     = "X-Zc-Timeout"
	//HEADER_DEV_ID       = "x-zc-developer-id"
)

type FastReqClient struct {
	reqClient                       *fasthttp.Client
	timeout                         int
	maxConnectionWaitTimeoutSeconds int
	commonTimeoutSeconds            int
	maxConnPerHost                  int
	maxConCurrency                  int
	maxIdleConnDuration             int
	maxIdemponentCallAttempts       int
}

func NewFastReqClient(timeout, dailTimeout, maxConnsPerHost,
	maxConnectionWaitTimeoutSeconds, maxIdleConnDuration, maxIdemponentCallAttempts int) *FastReqClient {

	client := &FastReqClient{
		timeout:              timeout,
		commonTimeoutSeconds: dailTimeout,
		maxConnPerHost:       maxConnsPerHost,
		maxConCurrency:       0,

		maxConnectionWaitTimeoutSeconds: maxConnectionWaitTimeoutSeconds,
		maxIdleConnDuration:             maxIdleConnDuration,
		maxIdemponentCallAttempts:       maxIdemponentCallAttempts,
	}
	client.initClient()
	return client
}

/**
 * @Description: 获取http客户端
 * @Author: LiuQHui
 * @Date 2022-04-13 18:53:22
**/
func (fc *FastReqClient) initClient() {
	fc.reqClient = &fasthttp.Client{
		TLSConfig: &tls.Config{InsecureSkipVerify: true},
		// 读超时时间,不设置read超时,可能会造成连接复用失效
		ReadTimeout: time.Second * time.Duration(fc.commonTimeoutSeconds),
		// 写超时时间
		WriteTimeout: time.Second * time.Duration(fc.commonTimeoutSeconds),
		// 5秒后，关闭空闲的活动连接
		MaxIdleConnDuration: time.Second * time.Duration(fc.maxIdleConnDuration),

		// Maximum duration for waiting for a free connection.
		// By default will not waiting, return ErrNoFreeConns immediately
		MaxConnWaitTimeout:        time.Second * time.Duration(fc.maxConnectionWaitTimeoutSeconds),
		MaxIdemponentCallAttempts: fc.maxIdemponentCallAttempts,

		// Keep-alive connections are closed after this duration.
		MaxConnDuration: time.Second * time.Duration(fc.maxIdleConnDuration),
		MaxConnsPerHost: fc.maxConnPerHost,

		// 当true时,从请求中去掉User-Agent标头
		NoDefaultUserAgentHeader: true,
		// 当true时，header中的key按照原样传输，默认会根据标准化转化
		DisableHeaderNamesNormalizing: true,
		//当true时,路径按原样传输，默认会根据标准化转化
		DisablePathNormalizing: true,
		Dial: (&fasthttp.TCPDialer{
			// 最大并发数，0表示无限制
			Concurrency: fc.maxConCurrency,
			// 将 DNS 缓存时间从默认分钟增加到一小时
			DNSCacheDuration: time.Hour,
		}).Dial,
	}
}

/**
 * @Description: 发起Get请求
**/
func (fc *FastReqClient) FastGetWithDo(url string, params string) string {
	// 获取客户端
	// 从请求池中分别获取一个request、response实例
	req, resp := fasthttp.AcquireRequest(), fasthttp.AcquireResponse()
	// 回收实例到请求池
	defer func() {
		fasthttp.ReleaseRequest(req)
		fasthttp.ReleaseResponse(resp)
	}()
	// 设置请求方式
	req.Header.SetMethod(fasthttp.MethodGet)
	// 设置请求地址
	req.SetRequestURI(url)
	if len(params) > 0 {
		req.URI().SetQueryString(params)
	}
	// 设置header信息
	req.Header.SetContentType(JSON_CONTENT_TYPE)
	// 发起请求
	if err := fc.reqClient.DoTimeout(req, resp, time.Second*time.Duration(fc.timeout)); err != nil {
		fmt.Println("req err ", err)
		return err.Error()
	}
	// 读取结果
	return string(resp.Body())
}

/**
 * @Description: post请求
 * @Author: LiuQHui
 * @Return string
 * @Date 2022-04-14 18:23:06
**/
func (fc *FastReqClient) FastPostRawWithDo(url string, paramsObj string) (string, error) {
	// 获取客户端
	// 从请求池中分别获取一个request、response实例
	req, resp := fasthttp.AcquireRequest(), fasthttp.AcquireResponse()
	// 回收到请求池
	defer func() {
		fasthttp.ReleaseRequest(req)
		fasthttp.ReleaseResponse(resp)
	}()
	// 设置请求方式
	req.Header.SetMethod(fasthttp.MethodPost)
	// 设置请求地址
	req.SetRequestURI(url)
	// 设置请求ContentType
	req.Header.SetContentType(JSON_CONTENT_TYPE)
	// 设置参数
	marshal, _ := json.Marshal(paramsObj)
	req.SetBodyRaw(marshal)
	// 发起请求
	if err := fc.reqClient.DoTimeout(req, resp, time.Second*time.Duration(fc.timeout)); err != nil {
		log.Errorf("fasthttp req post error: %v", err)
		return "", err
	}
	// 读取结果
	return string(resp.Body()), nil
}

func (fc *FastReqClient) FastPostDoWithReturnObj(url string, paramsObj interface{}, returnObj interface{}) error {
	// 获取客户端
	// 从请求池中分别获取一个request、response实例
	req, resp := fasthttp.AcquireRequest(), fasthttp.AcquireResponse()
	// 回收到请求池
	defer func() {
		fasthttp.ReleaseRequest(req)
		fasthttp.ReleaseResponse(resp)
	}()
	// 设置请求方式
	req.Header.SetMethod(fasthttp.MethodPost)
	// 设置请求地址
	req.SetRequestURI(url)
	// 设置请求ContentType
	req.Header.SetContentType(JSON_CONTENT_TYPE)
	// 设置参数
	marshal, _ := json.Marshal(paramsObj)
	req.SetBodyRaw(marshal)

	start := time.Now()
	// 发起请求
	if err := fc.reqClient.DoTimeout(req, resp, time.Second*time.Duration(fc.timeout)); err != nil {
		log.Errorf("fasthttp req post error: %v", err)
		return err
	}
	end := time.Now()
	log.Infof("request url: %s, parameters: %s, response: %s, consume: %v", url, string(marshal), string(resp.Body()), end.Sub(start))
	if err := json.Unmarshal(resp.Body(), &returnObj); err != nil {
		log.Errorf("fasthttp req post error: %v", err)
		return err
	}
	// 读取结果
	return nil
}

//func (fc *FastReqClient) FastZObj(url string, obj ac.ZObject, domain, subDomain string) (string, error) {
//	// 获取客户端
//	// 从请求池中分别获取一个request、response实例
//	req, resp := fasthttp.AcquireRequest(), fasthttp.AcquireResponse()
//	// 回收到请求池
//	defer func() {
//		fasthttp.ReleaseRequest(req)
//		fasthttp.ReleaseResponse(resp)
//	}()
//	// 设置请求方式
//	req.Header.SetMethod(fasthttp.MethodPost)
//	// 设置请求地址
//	req.SetRequestURI(url)
//	// 设置请求ContentType
//	req.Header.SetContentType(ZcObject)
//	if len(domain) > 0 {
//		req.Header.Add(HEADER_DOMAIN_ID, domain)
//	}
//	if len(subDomain) > 0 {
//		req.Header.Add(HEADER_SUBDOMAIN_ID, subDomain)
//	}
//	req.Header.Add(HEADER_TIME_OUT, "8000")
//	req.Header.Add(HEADER_DEV_ID, "999")
//	// 设置参数
//	marshal, _ := json.Marshal(obj)
//	req.SetBodyRaw(marshal)
//	// 发起请求
//	if err := fc.reqClient.DoTimeout(req, resp, time.Second*time.Duration(fc.timeout)); err != nil {
//		log.Errorf("fasthttp req post error: %v", err)
//		return "", err
//	}
//	// 读取结果
//	return string(resp.Body()), nil
//}
